package cn.quang.search.admin.service.impl;

import cn.quang.search.admin.entity.dto.Operator;
import cn.quang.search.admin.entity.dto.Result;
import cn.quang.search.admin.entity.po.*;
import cn.quang.search.admin.entity.vo.logicdic.LogicTableFieldDicRequest;
import cn.quang.search.admin.mapper.*;
import cn.quang.search.admin.service.IEntityLogicTableFieldDicService;
import cn.quang.search.admin.service.ISearchConfigChangeService;
import cn.quang.search.admin.service.common.RedisService;
import cn.quang.search.admin.utils.AssertUtils;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author:  Entity Generator
 * @since:  2024-02-28 10:26:15
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class EntityLogicTableFieldDicService implements IEntityLogicTableFieldDicService {

	private final EntityFieldDicMapper entityFieldDicMapper;
	private final EntityLogicTableFieldDicMapper entityLogicTableFieldDicMapper;
	private final EntityLogicTableMapper entityLogicTableMapper;
	private final SearchSceneMapper searchSceneMapper;
	private final SearchSceneConfigMapper searchSceneConfigMapper;

	private final ISearchConfigChangeService searchConfigChangeService;
	private final RedisService redisService;
	private static final String LOCK_KEY = "CRM3$ENTITY_LOGIC_TABLE_FIELD_DIC$";
	private static final int EXPIRE_SECONDS = 60;

	/**
	 * 逻辑表下的字段映射字典
	 * @param operator 操作人
	 * @param request 表名称
	 * @return 添加结果
	 */
	@Override
	public Result<?> addOrUpdate(Operator operator, LogicTableFieldDicRequest request){
		Result<?> methodResult = new Result<>();

		// 存储增删改的表名称，用于输出日志
		List<String> newLogicTableFieldDices = Lists.newArrayList();
		List<String> modifyLogicTableFieldDices = Lists.newArrayList();
		List<String> deleteLogicTableFieldDices = Lists.newArrayList();

		long logicTableId = request.getLogicTableId();
		AssertUtils.argumentNegativeOrZero(logicTableId, "必须提供逻辑表");

		long dicBelongTableId = request.getDicBelongTableId();
		AssertUtils.argumentNegativeOrZero(dicBelongTableId, "请提供用于生成自定义字典的真实表");

		List<LogicTableFieldDicRequest.TableFieldDicRequest> requestLogicTableFieldDices = request.getFieldDices();
		if(CollectionUtils.isEmpty(requestLogicTableFieldDices)) {
			requestLogicTableFieldDices = Lists.newArrayList();
		}

		Date now = new Date();

		Set<Long> existFieldDices = Sets.newHashSet();
		for (LogicTableFieldDicRequest.TableFieldDicRequest logicTableFieldDic : requestLogicTableFieldDices) {
			AssertUtils.argumentBlank(logicTableFieldDic.getDic(), "存在未填写Dic的自定义字典项");
			AssertUtils.argumentBlank(logicTableFieldDic.getName(), "存在未填写名称的自定义字典项");
			AssertUtils.argumentNegativeOrZero(logicTableFieldDic.getFieldDicId(), "存在未关联通用字典的自定义字典项");
			AssertUtils.argumentNegativeOrZero(logicTableFieldDic.getQueryFieldType(), "存在未指定字段查询类型的自定义字典项");
			AssertUtils.argumentNegativeOrZero(logicTableFieldDic.getResultFieldType(), "存在未指定字段返回类型的自定义字典项");
			if(existFieldDices.contains(logicTableFieldDic.getFieldDicId())) {
				EntityFieldDic entityFieldDic = entityFieldDicMapper.selectById(logicTableFieldDic.getFieldDicId());
				return methodResult.changeErr("关联通用字典" + (entityFieldDic != null ? (entityFieldDic.getDic() + "(" + entityFieldDic.getName() + ")") : "未知") + "重复，请检查！");
			}
			existFieldDices.add(logicTableFieldDic.getFieldDicId());
			if(StringUtils.isBlank(logicTableFieldDic.getResultFieldDefaultValue())){
				logicTableFieldDic.setResultFieldDefaultValue(StringUtils.EMPTY);
			}
		}

		String uniqueKey = LOCK_KEY + operator.getOperatorId() + "$" + logicTableId;
		String requestId = UUID.randomUUID().toString();
		if(redisService.tryLock(uniqueKey, requestId, EXPIRE_SECONDS)) {
			try {
				List<EntityLogicTableFieldDic> logicTableFieldDices = entityLogicTableFieldDicMapper.selectByLogicTableId(logicTableId);
				if(logicTableFieldDices == null) { logicTableFieldDices = Lists.newArrayList(); }
				Map<String, EntityLogicTableFieldDic> logicTableFieldDicMap = logicTableFieldDices.stream().collect(Collectors.toMap(EntityLogicTableFieldDic::getDic, v -> v));
				Map<String, LogicTableFieldDicRequest.TableFieldDicRequest> requestFieldDicMap = requestLogicTableFieldDices.stream().collect(Collectors.toMap(LogicTableFieldDicRequest.TableFieldDicRequest::getDic, v -> v));

				// 执行删除(解除自定义字典和逻辑表的关联关系，需要校验是否存在某个场景基于该逻辑表关联了该自定义字典，如果存在，则应该先解除场景下的关联关系)
				List<Long> deleteIds = Lists.newArrayList();
				for (EntityLogicTableFieldDic logicTableFieldDic : logicTableFieldDices) {
					String dic = logicTableFieldDic.getDic();
					if(!requestFieldDicMap.containsKey(dic)){
						List<SearchSceneConfig> searchSceneRelateDices = searchSceneConfigMapper.selectByFieldDicId(logicTableFieldDic.getFieldDicId());
						List<SearchSceneConfig> searchSceneRelateTables = searchSceneConfigMapper.selectByLogicTableId(logicTableId);
						if(CollectionUtils.isNotEmpty(searchSceneRelateDices) && CollectionUtils.isNotEmpty(searchSceneRelateTables)) {
							Set<Long> sceneIds = searchSceneRelateDices.stream().map(SearchSceneConfig::getSceneId).collect(Collectors.toSet());
							for (SearchSceneConfig config : searchSceneRelateTables) {
								if(sceneIds.contains(config.getSceneId())) {
									SearchScene scene = searchSceneMapper.selectById(config.getSceneId());
									EntityFieldDic entityFieldDic = entityFieldDicMapper.selectById(logicTableFieldDic.getFieldDicId());
									return methodResult.changeErr(String.format("查询场景(%s)基于当前的逻辑表关联了与自定义字典(%s)链接的通用字典(%s)，必须先解除场景上的关联后，方可在逻辑表上解绑该自定义字典", String.format("%s(%s)", scene.getCode(), scene.getName()), String.format("%s(%s)", logicTableFieldDic.getDic(), logicTableFieldDic.getName()), String.format("%s(%s)", entityFieldDic.getDic(), entityFieldDic.getName())));
								}
							}
						}
						// 删除
						deleteIds.add(logicTableFieldDic.getId());
						deleteLogicTableFieldDices.add(logicTableFieldDic.getDic());
					}
				}
				for (Long id : deleteIds) { entityLogicTableFieldDicMapper.deleteById(id); }

				// 比较更新 ： 存在的更新，不存在的新增，未出现在请求中的删除
				for (LogicTableFieldDicRequest.TableFieldDicRequest logicTableFieldDicRequest : requestLogicTableFieldDices) {
					EntityLogicTableFieldDic logicTableFieldDic = logicTableFieldDicMap.get(logicTableFieldDicRequest.getDic());
					if(logicTableFieldDic != null){
						// 已存在的自定义字典，执行更新
						logicTableFieldDic.setName(logicTableFieldDicRequest.getName());
						logicTableFieldDic.setFieldDicId(logicTableFieldDicRequest.getFieldDicId());
						logicTableFieldDic.setQueryFieldType(logicTableFieldDicRequest.getQueryFieldType());
						logicTableFieldDic.setResultFieldType(logicTableFieldDicRequest.getResultFieldType());
						logicTableFieldDic.setResultFieldDefaultValue(logicTableFieldDicRequest.getResultFieldDefaultValue());
						logicTableFieldDic.setInTerms(logicTableFieldDicRequest.isInTerms());
						logicTableFieldDic.setSupportQuery(logicTableFieldDicRequest.isSupportQuery());
						logicTableFieldDic.setSupportSort(logicTableFieldDicRequest.isSupportSort());
						logicTableFieldDic.setModifierId(operator.getOperatorId());
						logicTableFieldDic.setModifyTime(now);
						entityLogicTableFieldDicMapper.updateById(logicTableFieldDic);
						modifyLogicTableFieldDices.add(logicTableFieldDic.getDic());
					} else {
						// 新增
						logicTableFieldDic = new EntityLogicTableFieldDic();
						logicTableFieldDic.setLogicTableId(logicTableId);
						logicTableFieldDic.setFieldDicId(logicTableFieldDicRequest.getFieldDicId());
						logicTableFieldDic.setDic(logicTableFieldDicRequest.getDic());
						logicTableFieldDic.setName(logicTableFieldDicRequest.getName());
						logicTableFieldDic.setQueryFieldType(logicTableFieldDicRequest.getQueryFieldType());
						logicTableFieldDic.setResultFieldType(logicTableFieldDicRequest.getResultFieldType());
						logicTableFieldDic.setResultFieldDefaultValue(logicTableFieldDicRequest.getResultFieldDefaultValue());
						logicTableFieldDic.setInTerms(logicTableFieldDicRequest.isInTerms());
						logicTableFieldDic.setSupportQuery(logicTableFieldDicRequest.isSupportQuery());
						logicTableFieldDic.setSupportSort(logicTableFieldDicRequest.isSupportSort());
						logicTableFieldDic.setCreatorId(operator.getOperatorId());
						logicTableFieldDic.setCreateTime(now);
						logicTableFieldDic.setModifierId(operator.getOperatorId());
						logicTableFieldDic.setModifyTime(now);
						entityLogicTableFieldDicMapper.insert(logicTableFieldDic);
						newLogicTableFieldDices.add(logicTableFieldDicRequest.getDic());
					}
				}
			} catch (Exception e) {
				log.error("更新逻辑表字段失败", e);
				return methodResult.changeErr("更新逻辑表字段失败");
			} finally {
				redisService.releaseLock(uniqueKey, requestId);
			}
		} else {
			return methodResult.changeErr("请不要频繁操作！");
		}

		entityLogicTableMapper.update(new UpdateWrapper<EntityLogicTable>().lambda().set(EntityLogicTable::getDicBelongTableId, dicBelongTableId).eq(EntityLogicTable::getId, logicTableId));
		searchConfigChangeService.triggerByLogicTable(logicTableId);

		log.info(String.format("逻辑表新增字典%s，修改字典%s，删除字典%s", newLogicTableFieldDices, modifyLogicTableFieldDices, deleteLogicTableFieldDices));
		return methodResult;
	}

}
